import type { AxiosRequestConfig, Canceler } from 'axios';
import axios from 'axios';

type YXRequestConfig = AxiosRequestConfig & {
  headers?: any;
  noToken?: boolean; // 是否不需要token，默认false
  isLoading?: boolean; // 是否请求时开启全局Loading，默认false
  loadingTip?: string; // 全局Loading的提示
};
type res<T> = (value: T) => void;
type rej = (value: string) => void;
type TData<T> = {
  canceler: Canceler;
  config: YXRequestConfig;
  data: {
    data: Promise<T>;
    resolve: res<T>;
    reject: rej;
  };
};

/**
 * 重复请求实例
 */
export default class DuplicateRequest {
  constructor() {
    //
  }
  #pendingRequest = new Map<string, TData<unknown>>();
  /**
   *
   * @param config 获取请求唯一key值
   * @returns
   */
  generateReqKey = (config: YXRequestConfig) => {
    const { url, params } = config;
    const srt = new URLSearchParams(params);
    const queryString = `${url}?${srt.toString()}`;
    return queryString;
  };

  /**
   *
   * @param config 填加pendingRequest
   * @returns
   */
  addPendingRequest = (config: YXRequestConfig) => {
    const requestKey = this.generateReqKey(config);
    let resolve: res<unknown>;
    let reject: rej;
    const request: Promise<unknown> = new Promise((res, rej) => {
      resolve = res;
      reject = rej;
    });

    config.cancelToken =
      config.cancelToken ||
      new axios.CancelToken((cancel) => {
        if (!this.#pendingRequest.has(requestKey)) {
          this.#pendingRequest.set(requestKey, {
            canceler: cancel,
            config: config,
            data: {
              data: request,
              resolve,
              reject
            }
          });
        }
      });
  };

  /**
   *
   * @param config 检查是否存在重复请求，若存在则取消已发的请求。
   */
  removePendingRequest = (config: YXRequestConfig) => {
    const requestKey = this.generateReqKey(config);

    if (this.#pendingRequest.has(requestKey)) {
      const cancelToken = this.#pendingRequest.get(requestKey);
      const res = cancelToken?.data.data;
      cancelToken?.canceler(res as any);
    }
  };

  /**
   *
   * @param config 请求成功返回数据
   */
  changeRequest = <T>(config: YXRequestConfig, response: T, flag: boolean) => {
    const requestKey = this.generateReqKey(config);
    if (this.#pendingRequest.has(requestKey)) {
      const cancelToken = this.#pendingRequest.get(requestKey);
      if (cancelToken) {
        if (flag) {
          cancelToken.data.resolve(response);
        } else {
          cancelToken.data.reject(response as any);
          this.#pendingRequest.delete(requestKey);
        }
      }
    } else {
      throw new Error('未知请求');
    }
  };
}
